package com.homedo.distributed.id.client.gen.service;

import com.homedo.common.exception.HomedoException;
import com.homedo.distributed.id.client.gen.buffer.GenBuffer;
import com.homedo.distributed.id.client.gen.buffer.IdIRRegularityBuffer;
import com.homedo.distributed.id.client.gen.buffer.IdRegularityBuffer;
import com.homedo.distributed.id.client.gen.buffer.NoIRRegularityBuffer;
import com.homedo.distributed.id.client.gen.command.GenCommand;
import com.homedo.distributed.id.client.gen.command.GenCommandFactory;
import com.homedo.distributed.id.client.gen.constants.GenExecutorConstants;
import com.homedo.distributed.id.client.gen.constants.GenTypeConstants;
import com.homedo.distributed.id.client.gen.exception.GenException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

public class GenBufferService {

    private final static Map<String, GenBuffer<String>> GEN_BUFFER_CACHE = new ConcurrentHashMap<>();

    private ExecutorService preInitBufferExecutor = GenExecutorConstants.PRE_INIT_BUFFER_EXECUTOR;

    private final static GenBufferService INSTANCE = new GenBufferService();

    private static final Logger _LOGGER = LoggerFactory.getLogger(GenBufferService.class);

    private GenBufferService() {
    }

    public void preInit(String bizTag, int genType, int cacheSize) {
        this.preInitBufferExecutor.execute(new Runnable() {
            @Override
            public void run() {
                GenBuffer<String> genBuffer = getGenBuffer(bizTag, genType, cacheSize);
                genBuffer.init();
            }
        });

    }


    public String gen(String bizTag, int genType, int cacheSize) {
        GenBuffer<String> genBuffer = this.getGenBuffer(bizTag, genType, cacheSize);
        GenCommand<String> genCommand = this.getGenCommand(bizTag, genType, genBuffer);

        try {
            String gen = (String) genCommand.queue().get();
            if (gen.startsWith(GenBuffer.DEFAULT_ERROR_ID)) {
                throw new GenException("[获取GEN失败:" + gen + "]");
            }
            return gen;
        } catch (Exception ex) {
            _LOGGER.error("[获取GEN失败:{}#{}]", bizTag, genType, ex);
            throw new GenException("[获取GEN失败]");
        }
    }

    private GenCommand<String> getGenCommand(String bizTag, int genType, GenBuffer<String> genBuffer) {
        return GenCommandFactory.create(bizTag, genType, genBuffer);
    }

    private GenBuffer<String> getGenBuffer(String bizTag, int genType, int cacheSize) {
        GenBuffer<String> genBuffer = GEN_BUFFER_CACHE.get(bizTag);
        if (genBuffer == null) {
            GenBuffer<String> newGenBuffer = this.newGenBuffer(bizTag, genType, cacheSize);

            GenBuffer<String> oldGenBuffer = GEN_BUFFER_CACHE.putIfAbsent(bizTag, newGenBuffer);
            if (oldGenBuffer != null) {
                genBuffer = oldGenBuffer;
            } else {
                genBuffer = newGenBuffer;
            }
        }
        return genBuffer;
    }

    private GenBuffer<String> newGenBuffer(String bizTag, int genType, int cacheSize) {
        GenBuffer genBuffer;
        if (genType == GenTypeConstants.ID_REGULARITY) {
            genBuffer = new IdRegularityBuffer(bizTag, cacheSize);
        } else if (genType == GenTypeConstants.ID_IRREGULARITY) {
            genBuffer = new IdIRRegularityBuffer(bizTag, cacheSize);
        } else if (genType == GenTypeConstants.NO_IRREGULARITY) {
            genBuffer = new NoIRRegularityBuffer(bizTag, cacheSize);
        } else {
            throw new HomedoException("[不支持的genType类型：" + genType + "]");
        }
        return genBuffer;
    }

    public static GenBufferService getInstance() {
        return INSTANCE;
    }
}
